package com.meatball.authorization.config.filter

import com.meatball.authorization.config.JwtComponent
import com.meatball.authorization.enum.RoleEnum
import com.meatball.core.config.AUTHORIZATION
import com.meatball.core.config.BEARER
import com.meatball.core.config.TOKEN
import jakarta.servlet.FilterChain
import jakarta.servlet.ServletException
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.stereotype.Component
import org.springframework.util.StringUtils
import org.springframework.web.filter.OncePerRequestFilter
import java.io.IOException

@Component
class JwtAuthenticationFilter(
        private val jwtComponent: JwtComponent,
        private val userDetailsService: UserDetailsService,
        private val stringRedisTemplate: StringRedisTemplate
) : OncePerRequestFilter() {
    @Throws(ServletException::class, IOException::class)
    override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
        logger.info("当前角色：${RoleEnum.ADMIN.name}")
        logger.info("JwtAuthenticationFilter: 开始过滤请求")
        // 判断请求是否为登录请求，如果是登录请求则不进行处理
        if (request.servletPath.contains("/api/auth/login")) {
            filterChain.doFilter(request, response)
            return
        }
        // 从header中获取token
        val token = request.getHeader(AUTHORIZATION)
        // 如果不存在Token或者Token不已Bearer开头，则不进行处理
        if (token == null || !token.startsWith(BEARER)) {
            filterChain.doFilter(request, response)
            return
        }
        // 取出token信息
        val jwt = token.substring(7).trim()
        logger.info("当前TOKEN：$jwt")
        // 获取用户名
        val username = jwtComponent.extractUsername(jwt)
        logger.info("JwtAuthenticationFilter: 提取的用户名 - $username")
        // SecurityContextHolder 中的 Authentication 为空时，才进行处理
        if (StringUtils.hasText(username) && SecurityContextHolder.getContext().authentication == null) {
            logger.info("JwtAuthenticationFilter: 当前SecurityContext中没有认证信息，尝试认证用户 - $username")

            val userDetails = userDetailsService.loadUserByUsername(username)
            logger.info("JwtAuthenticationFilter: 成功加载用户详情")

            val isTokenValid = stringRedisTemplate.hasKey(TOKEN + userDetails.username)
            if (jwtComponent.isTokenValid(jwt, userDetails) && isTokenValid) {
                val authToken = UsernamePasswordAuthenticationToken(
                    userDetails, // 用户信息
                    null,
                    userDetails.authorities // 用户的权限
                )
                // 访问信息
                authToken.details = WebAuthenticationDetailsSource().buildDetails(request)

                // 在设置安全上下文之前打印日志
                logger.info("JwtAuthenticationFilter: 认证前的SecurityContext认证信息 - ${SecurityContextHolder.getContext().authentication}")

                logger.info("认证情况：${ authToken.isAuthenticated }")
                // 将用户信息以及权限保存到 SecurityContextHolder 的上下文中，方便后续使用
                // 例如：获取当前用户 id，获取当前用户权限等等
                SecurityContextHolder.getContext().authentication = authToken

                // 在设置安全上下文之后打印日志
                logger.info("JwtAuthenticationFilter: 认证后的SecurityContext认证信息 - ${SecurityContextHolder.getContext().authentication}")
            } else {
                logger.info("JwtAuthenticationFilter: Token无效或者不存在于Redis中")
            }
        } else {
            logger.info("JwtAuthenticationFilter: SecurityContext已经有认证信息或者用户名为空")
        }
        filterChain.doFilter(request, response)
        logger.info("JwtAuthenticationFilter: 结束过滤请求")
    }
}